﻿using UnityEngine;
using System.Collections;

public enum GameState
{
    menu,
    game
}

public enum FadeDir
{
    inF,
    outF
}

public struct FadingParameters
{
    public float startAlpha;
    public float endAlpha;
    public float time;  
}

public class PersistentManagerScript : MonoBehaviour 
{
    public GameObject game;
    public GameObject menu;
    public GameObject addedScorePrefab;
    public GameObject backGround;
    public float fadeInTime;
    public float fadeMenuOutTime;
    public float fadeGameOutTime;
    public float fadeMin;
    public float fadeMenuMax;
    public float fadeGameMax;
    private float currentScore;
    private GameState gamestate = GameState.menu;
    private bool isFading = false;

	void Start()
    {
        currentScore = 0;
        menu.GetComponent<MenuScript>().Open(fadeInTime);
        Fade(fadeMenuMax, fadeMin, fadeInTime);
        LastFace.instance.InstantiateLastface();
        game.SetActive(false);
        Physics.gravity = new Vector3(0f, 0f, 9.81f);
	}   
	
	void Update() 
    {
        if (Input.GetButtonDown("Jump"))
        {
            SetMaxScore(0);
        }
	}

    public void SetMaxScore(float score)
    {      
        PlayerPrefs.SetFloat("MaxScore", score);  
    }

    public void SetState(GameState state)
    {
        gamestate = state;

        switch (state)
        {           
            case GameState.game:
                Fade(FadeDir.inF);
                LastFace.instance.DestroyFace();
                menu.SetActive(false);
                game.SetActive(true);
                game.GetComponent<GameScript>().GameStartInitialization();
                break;
            case GameState.menu:
                Fade(FadeDir.inF);
                PlayerPrefs.SetFloat("ResentScore", currentScore);
                currentScore = 0;
                game.GetComponent<GameScript>().Reset();
                menu.SetActive(true);
                game.SetActive(false);
                menu.GetComponent<MenuScript>().Open(fadeInTime);
                LastFace.instance.InstantiateLastface();
                break;
            default:
                break;
        }
    }

    public GameState GetState()
    {
        return gamestate;
    }

    public float GetMaxScore()
    {
        return PlayerPrefs.GetFloat("MaxScore");
    }

    public float GetRecentScore()
    {
        return PlayerPrefs.GetFloat("ResentScore");
    }

    public void AddToScore(float score)
    {
        currentScore += score;
        if (currentScore < 0)
            currentScore = 0;
        InstantiateAddedScore(score);      
        UpdateMaxScoreIfNeeded();
    }

    private void InstantiateAddedScore(float score)
    {
        string prefix = "+";
        Color color = Color.green;
        if (score < 0)
        {
            color = Color.red;
            prefix = " ";
        }

        Vector3 pos = new Vector3(0.02f, addedScorePrefab.transform.position.y, addedScorePrefab.transform.position.z);
        GameObject newscore = ObjectPool.instance.Instantiate(addedScorePrefab, pos, new Quaternion(0, 0, 0, 0)) as GameObject;
        float time = 0.3f;
        float distance = 0.05f;
        newscore.GetComponent<GUIText>().text = prefix + score.ToString();
        newscore.GetComponent<GUIText>().color = color;
        newscore.GetComponent<GUIText>().anchor = TextAnchor.UpperLeft;
        GetComponent<Eezing>().EezOut(EezingMethod.toDown, newscore, newscore.transform.position, time, distance);
        newscore.GetComponent<FadeOutScript>().FadeOut(time);
    }

    public void InstantiateAddedTime(float addedTime)
    {
        string prefix = "+";
        Color color = Color.green;
        if (addedTime < 0)
        {
            color = Color.red;
            prefix = " ";
        }

        Vector3 pos = new Vector3(0.98f, addedScorePrefab.transform.position.y, addedScorePrefab.transform.position.z);
        GameObject newtime = ObjectPool.instance.Instantiate(addedScorePrefab, pos, new Quaternion(0, 0, 0, 0)) as GameObject;
        float time = 0.3f;
        float distance = 0.05f;
        newtime.GetComponent<GUIText>().text = prefix + addedTime.ToString();
        newtime.GetComponent<GUIText>().color = color;
        newtime.GetComponent<GUIText>().anchor = TextAnchor.UpperRight;      
        GetComponent<Eezing>().EezOut(EezingMethod.toDown, newtime, newtime.transform.position, time, distance);
        newtime.GetComponent<FadeOutScript>().FadeOut(time);
    }

    public void ReduceScore(float score)
    {
        currentScore -= score;
    }

    public float GetCurrentScore()
    {
        return currentScore;
    }

    public void SetCurrentScore(float score)
    {
        currentScore = score;
        UpdateMaxScoreIfNeeded();
    }

    private void UpdateMaxScoreIfNeeded()
    {
        if (currentScore > GetMaxScore())
        {
            SetMaxScore(currentScore);
        }
    }

    public void Fade(FadeDir dir)
    {
        if (!isFading)
        {
            switch (dir)
            {
                case FadeDir.inF:
                    Fade(fadeMenuMax, fadeMin, fadeInTime);
                    break;

                case FadeDir.outF:
                    Fade(fadeMin, GetFadeMax(), GetFadeOuttime());
                    break;
            }
        }
    }

    public bool IsFading()
    {
        return isFading;
    }

    private float GetFadeOuttime()
    {
        if (gamestate == GameState.menu)
            return fadeMenuOutTime;

        else return fadeGameOutTime;
    }

    private float GetFadeMax()
    {
        if (gamestate == GameState.menu)
            return fadeMenuMax;

        else return fadeGameMax;
    }

    private void Fade(float startAlpha, float endAlpha, float time)
    {
        FadingParameters parameters;
        parameters.startAlpha = startAlpha;
        parameters.endAlpha = endAlpha;
        parameters.time = time;
        StartCoroutine("Fading", parameters);
    }

    private IEnumerator Fading(FadingParameters parameters)
    {
        isFading = true;
        float t = 0;
        while (t / parameters.time < 1)
        {
            t += Time.deltaTime;
            Color startColor = new Color(backGround.renderer.material.color.r,
                                         backGround.renderer.material.color.g,
                                         backGround.renderer.material.color.b,
                                         parameters.startAlpha);

            Color endColor = new Color(backGround.renderer.material.color.r,
                                         backGround.renderer.material.color.g,
                                         backGround.renderer.material.color.b,
                                         parameters.endAlpha);

            backGround.renderer.material.color = Color.Lerp(startColor, endColor, t / parameters.time);
            yield return null;
        }

        isFading = false;

        if (parameters.startAlpha < parameters.endAlpha)
        {
            Time.timeScale = 1.0f;
            SetNextState();
        }
    }

    private void SetNextState()
    {
        if (gamestate == GameState.menu)
            SetState(GameState.game);

        else
            SetState(GameState.menu);
    }
}

